package jrain.fw.core.log;

import java.lang.reflect.Constructor;

import jrain.fw.core.service.ServiceCfg;
import jrain.utils.lang.StringUtils;

/**
 * <pre>
 * 作者：3244924214@qq.com 
 * 描述： 日志工程，适配常见的日志框架
 * </pre>
 */
public class LoggerFactory {

	private static volatile Constructor<?> logConstructor;

	static {
		String logType = StringUtils.trimNull(System.getProperty(ServiceCfg.logType.getName()), ServiceCfg.logType.getValue());
		if (StringUtils.isEmpty(logType)) {
			if (logType.equalsIgnoreCase("slf4j")) {
				tryImplementation("org.slf4j.Logger", "jrain.fw.log.Slf4jImpl");
			} else if (logType.equalsIgnoreCase("log4j2")) {
				tryImplementation("org.apache.logging.log4j.Logger", "jrain.fw.log.Log4j2Impl");
			}
		}
		tryImplementation("org.slf4j.Logger", "jrain.fw.log.Slf4jImpl");
		tryImplementation("org.apache.logging.log4j.Logger", "jrain.fw.log.Log4j2Impl");
		if (logConstructor == null) {
			try {
				logConstructor = NoLoggingImpl.class.getConstructor(String.class);
			} catch (Exception e) {
				throw new IllegalStateException(e.getMessage(), e);
			}
		}
	}

	private static void tryImplementation(String testClassName, String implClassName) {
		if (logConstructor != null) {
			return;
		}

		try {
			classForName(testClassName);
			Class<?> implClass = classForName(implClassName);
			logConstructor = implClass.getConstructor(new Class[] { String.class });

			Class<?> declareClass = logConstructor.getDeclaringClass();
			if (!Logger.class.isAssignableFrom(declareClass)) {
				logConstructor = null;
			}

			try {
				if (null != logConstructor) {
					logConstructor.newInstance(LoggerFactory.class.getName());
				}
			} catch (Throwable t) {
				logConstructor = null;
			}

		} catch (Throwable t) {
		}
	}

	private static Class<?> classForName(String className) throws ClassNotFoundException {
		Class<?> clazz = null;
		try {
			clazz = getClassLoader().loadClass(className);
		} catch (Exception e) {
		}
		if (clazz == null) {
			clazz = Class.forName(className);
		}
		return clazz;
	}

	private static ClassLoader getClassLoader() {
		return Thread.currentThread().getContextClassLoader();
	}

	public static Logger getLogger(Class<?> clazz) {
		return getLogger(clazz.getName());
	}

	public static Logger getLogger(String loggerName) {
		try {
			return (Logger) logConstructor.newInstance(loggerName);
		} catch (Throwable t) {
			throw new RuntimeException("Error creating logger for logger '" + loggerName + "'.  Cause: " + t, t);
		}
	}
}
